<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/favicon.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon.png">
  <link rel="mask-icon" href="/images/favicon.png" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css">
  <link rel="stylesheet" href="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.css">


<script id="hexo-configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    hostname: new URL('https://codz-me.vercel.app').hostname,
    root: '/',
    scheme: 'Muse',
    version: '7.7.1',
    exturl: false,
    sidebar: {"position":"right","display":"post","padding":18,"offset":12,"onmobile":false},
    copycode: {"enable":false,"show_result":false,"style":null},
    back2top: {"enable":true,"sidebar":false,"scrollpercent":false},
    bookmark: {"enable":false,"color":"#222","save":"auto"},
    fancybox: true,
    mediumzoom: false,
    lazyload: false,
    pangu: false,
    comments: {"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},
    algolia: {
      appID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    },
    localsearch: {"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},
    path: '',
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}
  };
</script>

  <meta name="description" content="Bug Not Found">
<meta property="og:type" content="website">
<meta property="og:title" content="Code Is Poetry">
<meta property="og:url" content="https://codz-me.vercel.app/index.html">
<meta property="og:site_name" content="Code Is Poetry">
<meta property="og:description" content="Bug Not Found">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="laudukang">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://codz-me.vercel.app/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome: true,
    isPost: false
  };
</script>

  <title>Code Is Poetry</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-meta">

    <div>
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">Code Is Poetry</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
  </div>

  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>
</div>


<nav class="site-nav">
  
  <ul id="menu" class="menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-fw fa-home"></i>首页</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="fa fa-fw fa-user"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-fw fa-tags"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-fw fa-th"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-fw fa-archive"></i>归档</a>

  </li>
        <li class="menu-item menu-item-commonweal">

    <a href="/404/" rel="section"><i class="fa fa-fw fa-heartbeat"></i>公益 404</a>

  </li>
  </ul>

</nav>
</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content">
            

  <div class="posts-expand">
        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://codz-me.vercel.app/2019/11/20/opentsdb-query-optimization/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/head.png">
      <meta itemprop="name" content="laudukang">
      <meta itemprop="description" content="Bug Not Found">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Code Is Poetry">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2019/11/20/opentsdb-query-optimization/" class="post-title-link" itemprop="url">OpenTSDB 查询优化</a>
        </h1>

        <div class="post-meta">
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2020-03-10 10:50:49 10:50:49" itemprop="dateModified" datetime="2020-03-10T10:50:49+08:00">2020-03-10 10:50:49</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/OpenTSDB/" itemprop="url" rel="index">
                    <span itemprop="name">OpenTSDB</span>
                  </a>
                </span>
            </span>

          
            <span id="/2019/11/20/opentsdb-query-optimization/" class="post-meta-item leancloud_visitors" data-flag-title="OpenTSDB 查询优化" title="阅读次数">
                <span hidden class="leancloud-visitors-count"></span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h2 id="OpenTSDB-简介"><a href="#OpenTSDB-简介" class="headerlink" title="OpenTSDB 简介"></a>OpenTSDB 简介</h2><p><code>OpenTSDB</code>是一个基于HBase的可扩展时间序列数据库，支持数百万每秒的读写，与OpenTSDB的交互主要是通过运行一个或多个TSD来实现的。每个TSD是独立的，没有主设备，没有共享状态，因此您可以根据需要运行任意数量的 TSD，以处理向其施加的任何负载。</p>
<p><code>Cloudera Express</code>管理并运行了生产环境的 HDFS/HBase/ZooKeeper。</p>
<h2 id="项目背景"><a href="#项目背景" class="headerlink" title="项目背景"></a>项目背景</h2><p>OpenTSDB存储了SDN设备间的流量数据，粒度包括：源IP、目的IP、上下行流量、服务类型、协议等。</p>
<p>流量统计接口按时间区间直接查询了OpenTSDB的原始数据，未经Rollup处理。</p>
<h2 id="查询瓶颈"><a href="#查询瓶颈" class="headerlink" title="查询瓶颈"></a>查询瓶颈</h2><p>客户BJ联通反馈某台<code>SDN</code>设备11月初的流量统计接口返回超时。测试发现其他设备流量统计正常，联通设备查询时候有如下错误日志：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">16:14:13.466 ERROR [RegionClient.exceptionCaught] - Unexpected exception from downstream on [id: 0xbbc6970f, &#x2F;172.31.250.10:50790 &#x3D;&gt; &#x2F;172.31.120.131:16020]</span><br><span class="line">com.stumbleupon.async.CallbackOverflowError: Too many callbacks in Deferred@1273979129(state&#x3D;PENDING, result&#x3D;null, callback&#x3D;net.opentsdb.tsd.HttpJsonSerializer$1DPsResolver@682fd571 -&gt; net.opentsdb.tsd.HttpJsonSerializer$1DPsResolver@3061522a -&gt; net.opentsdb.tsd.HttpJsonSerializer$1DPsResolver@27fac471 -&gt; net.opentsdb.tsd.HttpJsonSerializer$1DPsResolver@17a290df -&gt; net.opentsdb.tsd.HttpJsonSerializer$1DPsResolver@1304b07 -&gt; </span><br><span class="line">&#x2F;&#x2F;....</span><br><span class="line">passthrough -&gt; passthrough) (size&#x3D;16383) when attempting to add cb&#x3D;net.opentsdb.tsd.HttpJsonSerializer$1DPsResolver@29bbd6fc@700176124, eb&#x3D;passthrough@1260931085</span><br></pre></td></tr></table></figure>

<p>Github上有人2016年就遇到该错误，<a href="https://github.com/OpenTSDB/opentsdb/issues/839" target="_blank" rel="noopener">CallbackOverflowError with many tag values</a>，issue至今未关闭</p>
<p>翻阅了OpenTSDB报错代码段</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// com.stumbleupon:async:1.4.1</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">Deferred</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">short</span> MAX_CALLBACK_CHAIN_LENGTH = (<span class="number">1</span> &lt;&lt; <span class="number">14</span>) - <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//....</span></span><br><span class="line">    <span class="comment">//com.stumbleupon.async.Deferred#addCallbacks</span></span><br><span class="line">    <span class="keyword">public</span> &lt;R, R2, E&gt; <span class="function">Deferred&lt;R&gt; <span class="title">addCallbacks</span><span class="params">(<span class="keyword">final</span> Callback&lt;R, T&gt; cb,</span></span></span><br><span class="line"><span class="function"><span class="params">                                               <span class="keyword">final</span> Callback&lt;R2, E&gt; eb)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (last_callback == callbacks.length) &#123;</span><br><span class="line">            <span class="keyword">final</span> <span class="keyword">int</span> oldlen = callbacks.length;</span><br><span class="line">            <span class="keyword">if</span> (oldlen == MAX_CALLBACK_CHAIN_LENGTH * <span class="number">2</span>) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> CallbackOverflowError(<span class="string">"Too many callbacks in "</span> + <span class="keyword">this</span></span><br><span class="line">                        + <span class="string">" (size="</span> + (oldlen / <span class="number">2</span>) + <span class="string">") when attempting to add cb="</span></span><br><span class="line">                        + cb + <span class="string">'@'</span> + cb.hashCode() + <span class="string">", eb="</span> + eb + <span class="string">'@'</span> + eb.hashCode());</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">final</span> <span class="keyword">int</span> len = Math.min(oldlen * <span class="number">2</span>, MAX_CALLBACK_CHAIN_LENGTH * <span class="number">2</span>);</span><br><span class="line">            <span class="keyword">final</span> Callback[] newcbs = <span class="keyword">new</span> Callback[len];</span><br><span class="line">            System.arraycopy(callbacks, next_callback,  <span class="comment">// Outstanding callbacks.</span></span><br><span class="line">                    newcbs, <span class="number">0</span>,            <span class="comment">// Move them to the beginning.</span></span><br><span class="line">                    last_callback - next_callback);  <span class="comment">// Number of items.</span></span><br><span class="line">            last_callback -= next_callback;</span><br><span class="line">            next_callback = <span class="number">0</span>;</span><br><span class="line">            callbacks = newcbs;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>MAX_CALLBACK_CHAIN_LENGTH</code>限制了<code>Deferred</code>链的长度，而进入到上面<code>addCallbacks</code>方法的为聚合分类后的每条数据，估计联通的问题就是处理数据超过了该限制。</p>
<p>测试也发现缩短联通设备的查询时间区间是能正常返回的，并且2019-11-06 8:00:00 - 2019-11-06 9:00:00的数据就近1.5W条返回，也就是说联通设备目的IP近1.5W个，大多数IP流量不多。</p>
<blockquote>
<p>Deferred类是Java库提供一些有用的构建模块去 构建高性能，多线程，异步的java应用。它的实现灵感来自Twisted的异步库（twisted.internet.defer）。<br>Deferred允许你轻松地构建异步的处理链，这个处理链必须触发，当一个异步的事件（I/O,RPC 以及其它）完成。它能被广泛用于构建异步API，在一个多线程服务器或者是客户端中。</p>
</blockquote>
<h2 id="着手解决"><a href="#着手解决" class="headerlink" title="着手解决"></a>着手解决</h2><p>OpenTSDB并不提供返回结果限制参数，至少2.4版本没有。</p>
<p>华为云CloudTable集成的OpenTSDB服务支持了结果限制，也就是query api提供了一个limit参数。</p>
<p>流量统计接口是统计该设备的<code>TOP10</code>流量，因此设置更大的MAX_CALLBACK_CHAIN_LENGTH没有意义：返回结果多，查询慢。</p>
<p>解决办法就是过滤进入到addCallback的数据大小：</p>
<p>1、OpenTSDB的查询最后准备返回结果的时候才通过三行代码过滤掉不在该时间区间的数据，</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//net/opentsdb/tsd/HttpJsonSerializer.java:835</span></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">final</span> DataPoint dp : dps) &#123;</span><br><span class="line">  <span class="keyword">if</span> (dp.timestamp() &lt; data_query.startTime() || </span><br><span class="line">      dp.timestamp() &gt; data_query.endTime()) &#123;</span><br><span class="line">    <span class="keyword">continue</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">//...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>因此一个优化就是在进入addCallback就过滤掉这一部分数据。</p>
<p>2、提供一个limit参数，限制返回结果集大小。这里分两步：一是进入addCallback前通过<code>TreeSet</code>自动排序，限制最多limit条数据会进入处理，二是OutputStream写入时候，排序后截取前limit条数据返回。</p>
<p>关键是提前过滤不在时间区间的数据点及TreeSet自动排序过滤掉大部分小流量的IP数据</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">HttpJsonSerializer</span> <span class="keyword">extends</span> <span class="title">HttpSerializer</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//net.opentsdb.tsd.HttpJsonSerializer#formatQueryAsyncV1</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Deferred&lt;ChannelBuffer&gt; <span class="title">formatQueryAsyncV1</span><span class="params">(<span class="keyword">final</span> TSQuery data_query,</span></span></span><br><span class="line"><span class="function"><span class="params">                                                      <span class="keyword">final</span> List&lt;DataPoints[]&gt; results, <span class="keyword">final</span> List&lt;Annotation&gt; globals)</span></span></span><br><span class="line"><span class="function">            <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">final</span> Deferred&lt;Object&gt; cb_chain = <span class="keyword">new</span> Deferred&lt;Object&gt;();</span><br><span class="line">        TreeSet&lt;Number&gt; numberTreeSet = LongStream.range(<span class="number">0</span> - limit, <span class="number">0</span>).mapToDouble(i -&gt; <span class="number">1.0</span> * i).boxed().collect(Collectors.toCollection(TreeSet::<span class="keyword">new</span>));</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (DataPoints[] separate_dps : results) &#123;</span><br><span class="line">            <span class="keyword">for</span> (DataPoints dps : separate_dps) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="comment">//filter empty dps, laudukang</span></span><br><span class="line">                    <span class="keyword">boolean</span> isDpsOk = <span class="keyword">false</span>;</span><br><span class="line"></span><br><span class="line">                    <span class="keyword">for</span> (<span class="keyword">final</span> DataPoint dp : dps) &#123;</span><br><span class="line">                        <span class="keyword">if</span> (dp.timestamp() &gt;= data_query.startTime() &amp;&amp;</span><br><span class="line">                                dp.timestamp() &lt;= data_query.endTime()) &#123;</span><br><span class="line">                            isDpsOk = <span class="keyword">true</span>;</span><br><span class="line">                            <span class="keyword">break</span>;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line"></span><br><span class="line">                    <span class="keyword">if</span> (isDpsOk &amp;&amp; limit &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                        Number dpsSum = dps.sumDps();</span><br><span class="line">                        <span class="keyword">if</span> (numberTreeSet.first().doubleValue() &lt; dpsSum.doubleValue()) &#123;</span><br><span class="line">                            numberTreeSet.pollFirst();</span><br><span class="line">                            numberTreeSet.add(dpsSum.doubleValue());</span><br><span class="line">                        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                            <span class="comment">//filter</span></span><br><span class="line">                            isDpsOk = <span class="keyword">false</span>;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line"></span><br><span class="line">                    <span class="keyword">if</span> (isDpsOk) &#123;</span><br><span class="line">                        cb_chain.addCallback(<span class="keyword">new</span> DPsResolver(dps));</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"Unexpected error durring resolution"</span>, e);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如query api传入参数包含limit，则先将数据写入到<code>ByteArrayOutputStream</code>（这样子源代码改动小），再从<code>ByteArrayOutputStream</code>中反序列化获得原响应数据，倒序并截取前limit条数据写入到<code>OutputStream</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//net.opentsdb.tsd.HttpJsonSerializer#sortDps</span></span><br><span class="line"><span class="meta">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">sortDps</span><span class="params">(<span class="keyword">long</span> limit, ByteArrayOutputStream stream, OutputStream output)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">    <span class="keyword">byte</span>[] content = stream.toByteArray();</span><br><span class="line">    TypeReference&lt;List&lt;Map&lt;String, Object&gt;&gt;&gt; typeReference = <span class="keyword">new</span> TypeReference&lt;List&lt;Map&lt;String, Object&gt;&gt;&gt;() &#123;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    List&lt;Map&lt;String, Object&gt;&gt; dataList = JSON.parseToObject(content, typeReference);</span><br><span class="line"></span><br><span class="line">    List&lt;Map&lt;String, Object&gt;&gt; resultMapList = dataList.stream()</span><br><span class="line">            .filter(m -&gt; !m.containsKey(<span class="string">"metric"</span>))</span><br><span class="line">            .collect(Collectors.toList());</span><br><span class="line"></span><br><span class="line">    List&lt;Map&lt;String, Object&gt;&gt; metricNodeMapList = dataList.stream()</span><br><span class="line">            .filter(m -&gt; m.containsKey(<span class="string">"metric"</span>))</span><br><span class="line">            .collect(Collectors.toList());</span><br><span class="line"></span><br><span class="line">    <span class="comment">//sum dps for sort</span></span><br><span class="line">    metricNodeMapList.forEach(m -&gt; &#123;</span><br><span class="line">        <span class="keyword">double</span> value = ((Map&lt;String, Object&gt;) m.get(<span class="string">"dps"</span>)).values().stream()</span><br><span class="line">                .mapToDouble(i -&gt; &#123;</span><br><span class="line">                    <span class="keyword">if</span> (i <span class="keyword">instanceof</span> Integer) &#123;</span><br><span class="line">                        <span class="keyword">return</span> ((Integer) i).doubleValue();</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">return</span> (<span class="keyword">double</span>) i;</span><br><span class="line">                &#125;)</span><br><span class="line">                .sum();</span><br><span class="line"></span><br><span class="line">        m.put(<span class="string">"sumDps"</span>, value);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    Comparator&lt;Map&lt;String, Object&gt;&gt; dpsSorter = Comparator.comparingDouble(m -&gt; (<span class="keyword">double</span>) m.get(<span class="string">"sumDps"</span>));</span><br><span class="line">    List&lt;Map&lt;String, Object&gt;&gt; metricLimitNodeMapList = metricNodeMapList.stream()</span><br><span class="line">            .sorted(dpsSorter.reversed()).limit(limit)</span><br><span class="line">            .collect(Collectors.toList());</span><br><span class="line"></span><br><span class="line">    resultMapList.addAll(metricLimitNodeMapList);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">final</span> JsonGenerator json = JSON.getFactory().createGenerator(output);</span><br><span class="line">    json.writeObject(resultMapList);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="编译测试"><a href="#编译测试" class="headerlink" title="编译测试"></a>编译测试</h2><p>参考<a href="http://opentsdb.net/docs/build/html/development/development.html" target="_blank" rel="noopener">OpenTSDB General Development</a> <code>Compiles OpenTSDB and generates a Debian package</code>，卸载官方版本后安装。</p>
<p>修改 <a href="https://github.com/laudukang/opentsdb-okhttp-client" target="_blank" rel="noopener">laudukang/opentsdb-okhttp-client</a> 让其支持<code>limit</code>查询参数。</p>
<p>测试显示查询耗时明显缩短，而且响应大小也减少了，不再返回几MB的json数据。</p>
<p>查询例子<br><code>POST /api/query?summary</code></p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"limit"</span>: <span class="number">10</span>,<span class="comment">//限制返回条目数，倒序</span></span><br><span class="line">  <span class="attr">"delete"</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="attr">"end"</span>: <span class="number">1573012800000</span>,</span><br><span class="line">  <span class="attr">"globalAnnotations"</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="attr">"msResolution"</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="attr">"noAnnotations"</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="attr">"queries"</span>: [</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="attr">"aggregator"</span>: <span class="string">"sum"</span>,</span><br><span class="line">      <span class="attr">"downsample"</span>: <span class="string">"0all-sum"</span>,</span><br><span class="line">      <span class="attr">"explicitTags"</span>: <span class="literal">false</span>,</span><br><span class="line">      <span class="attr">"filters"</span>: [</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="attr">"filter"</span>: <span class="string">"*"</span>,</span><br><span class="line">          <span class="attr">"groupBy"</span>: <span class="literal">true</span>,</span><br><span class="line">          <span class="attr">"tagk"</span>: <span class="string">"dst_ip"</span>,</span><br><span class="line">          <span class="attr">"type"</span>: <span class="string">"wildcard"</span></span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="attr">"filter"</span>: <span class="string">"CONNECTION_OVERSEAS"</span>,</span><br><span class="line">          <span class="attr">"groupBy"</span>: <span class="literal">false</span>,</span><br><span class="line">          <span class="attr">"tagk"</span>: <span class="string">"service_type"</span>,</span><br><span class="line">          <span class="attr">"type"</span>: <span class="string">"literal_or"</span></span><br><span class="line">        &#125;</span><br><span class="line">      ],</span><br><span class="line">      <span class="attr">"metric"</span>: <span class="string">"1164.conn.total.in"</span>,</span><br><span class="line">      <span class="attr">"preAggregate"</span>: <span class="literal">false</span>,</span><br><span class="line">      <span class="attr">"rate"</span>: <span class="literal">false</span>,</span><br><span class="line">      <span class="attr">"useMultiGets"</span>: <span class="literal">false</span></span><br><span class="line">    &#125;</span><br><span class="line">  ],</span><br><span class="line">  <span class="attr">"showQuery"</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="attr">"showStats"</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="attr">"showSummary"</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="attr">"showTSUIDs"</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="attr">"start"</span>: <span class="number">1572998400000</span>,</span><br><span class="line">  <span class="attr">"timezone"</span>: <span class="string">"UTC"</span>,</span><br><span class="line">  <span class="attr">"useCalendar"</span>: <span class="literal">false</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>response</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"metric"</span>: <span class="string">"1164.conn.total.in"</span>,</span><br><span class="line">    <span class="attr">"tags"</span>: &#123;</span><br><span class="line">      <span class="attr">"protocol"</span>: <span class="string">"TCP"</span>,</span><br><span class="line">      <span class="attr">"service_type"</span>: <span class="string">"CONNECTION_OVERSEAS"</span>,</span><br><span class="line">      <span class="attr">"dst_ip"</span>: <span class="string">"107.167.89.234"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">"aggregateTags"</span>: [</span><br><span class="line">      <span class="string">"src_ip"</span></span><br><span class="line">    ],</span><br><span class="line">    <span class="attr">"dps"</span>: &#123;</span><br><span class="line">      <span class="attr">"157296960"</span>: <span class="number">17588304652</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">"sumDps"</span>: <span class="number">17588304652</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"metric"</span>: <span class="string">"1164.conn.total.in"</span>,</span><br><span class="line">    <span class="attr">"tags"</span>: &#123;</span><br><span class="line">      <span class="attr">"src_ip"</span>: <span class="string">"240.16.1.109"</span>,</span><br><span class="line">      <span class="attr">"protocol"</span>: <span class="string">"TCP"</span>,</span><br><span class="line">      <span class="attr">"service_type"</span>: <span class="string">"CONNECTION_OVERSEAS"</span>,</span><br><span class="line">      <span class="attr">"dst_ip"</span>: <span class="string">"152.199.39.180"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">"aggregateTags"</span>: [],</span><br><span class="line">    <span class="attr">"dps"</span>: &#123;</span><br><span class="line">      <span class="attr">"157296960"</span>: <span class="number">9804591660</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">"sumDps"</span>: <span class="number">9804591660</span></span><br><span class="line">  &#125;,</span><br><span class="line">  </span><br><span class="line">  <span class="comment">//余下8条省略...</span></span><br><span class="line">]</span><br></pre></td></tr></table></figure>

<p>提供一个编译好的安装包：<br><a href="https://codz.me/d/opentsdb-2.4.0_all.deb" target="_blank" rel="noopener">Debian package: opentsdb-2.4.0_all.deb</a></p>
<p><a href="https://gofile.io/?c=ICGijr" target="_blank" rel="noopener">Debian package: opentsdb-2.4.0_all.deb Backup Url</a></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&gt;md5sum opentsdb-2.4.0_all.deb</span><br><span class="line">22c98200d548b04ef8048922c9886cd0  opentsdb-2.4.0_all.deb</span><br></pre></td></tr></table></figure>

<h2 id="推荐一个类库"><a href="#推荐一个类库" class="headerlink" title="推荐一个类库"></a>推荐一个类库</h2><p>推荐一个<code>OpenTSDB</code>Java类库<a href="https://github.com/laudukang/opentsdb-okhttp-client" target="_blank" rel="noopener">OpenTSDB Java Async Client</a>，封装了一下几个方法，开箱即用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">default</span> String <span class="title">buildUrl</span><span class="params">(String serviceUrl, String postApiEndPoint, ExpectResponse expectResponse)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="keyword">default</span> String <span class="title">pushDataPointsString</span><span class="params">(DataPointBuilder builder, ExpectResponse expectResponse)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="keyword">default</span> String <span class="title">pushQueriesString</span><span class="params">(QueryBuilder builder, ExpectResponse expectResponse)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="keyword">default</span> <span class="keyword">void</span> <span class="title">asyncPushDataPoints</span><span class="params">(DataPointBuilder builder, ExpectResponse expectResponse, Callback callback)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="keyword">default</span> QueryResponse <span class="title">pushQueries</span><span class="params">(QueryBuilder builder, ExpectResponse expectResponse)</span></span></span><br></pre></td></tr></table></figure>

<p>Spring boot init <code>OpenTSDBService</code> example:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> OpenTSDBService <span class="title">openTSDBService</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    List&lt;String&gt; openTSDBServerList = configProperties.getOpentsdbServer();</span><br><span class="line">    <span class="keyword">if</span> (CollectionUtils.isEmpty(openTSDBServerList)) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"empty opentsdb server url"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> () -&gt; openTSDBServerList;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Thanks to <a href="https://www.jetbrains.com/?from=OpenTSDB%20Java%20Async%20Client" target="_blank" rel="noopener">JetBrains</a>‘ support</p>
<img src="/2019/11/20/opentsdb-query-optimization/jetbrains_support.png" alt="jetbrains_support.png" title="">

<h2 id="部分资料"><a href="#部分资料" class="headerlink" title="部分资料"></a>部分资料</h2><ul>
<li><a href="https://github.com/laudukang/opentsdb" target="_blank" rel="noopener">laudukang/opentsdb</a></li>
<li><a href="https://github.com/laudukang/opentsdb-okhttp-client" target="_blank" rel="noopener">laudukang/opentsdb-okhttp-client</a></li>
<li><a href="http://opentsdb.net/" target="_blank" rel="noopener">OpenTSDB</a></li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://codz-me.vercel.app/2018/05/07/build-spark-cluster/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/head.png">
      <meta itemprop="name" content="laudukang">
      <meta itemprop="description" content="Bug Not Found">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Code Is Poetry">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2018/05/07/build-spark-cluster/" class="post-title-link" itemprop="url">Build Spark Cluster</a>
        </h1>

        <div class="post-meta">
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2018-06-09 15:00:52 15:00:52" itemprop="dateModified" datetime="2018-06-09T15:00:52+08:00">2018-06-09 15:00:52</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Linux/" itemprop="url" rel="index">
                    <span itemprop="name">Linux</span>
                  </a>
                </span>
            </span>

          
            <span id="/2018/05/07/build-spark-cluster/" class="post-meta-item leancloud_visitors" data-flag-title="Build Spark Cluster" title="阅读次数">
                <span hidden class="leancloud-visitors-count"></span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h2 id="Install-pssh-to-batch-config-spark-slaves"><a href="#Install-pssh-to-batch-config-spark-slaves" class="headerlink" title="Install pssh, to batch config spark slaves"></a>Install pssh, to batch config spark slaves</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.coms/parallel-ssh/pssh-2.3.1.tar.gz</span><br><span class="line"></span><br><span class="line">tar -xzvf pssh-2.3.1.tar.gz</span><br><span class="line"></span><br><span class="line">cd pssh-2.3.1</span><br><span class="line"></span><br><span class="line">python setup.py install</span><br></pre></td></tr></table></figure>

<p>使用参见：</p>
<ul>
<li><p><a href="http://www.cnblogs.com/lurenjiashuo/p/pssh.html" target="_blank" rel="noopener">使用PSSH批量操作Linux服务器</a></p>
</li>
<li><p><a href="https://tonydeng.github.io/2014/12/08/pssh/" target="_blank" rel="noopener">PSSH基本使用介绍</a></p>
</li>
</ul>
<h2 id="System-config-in-master"><a href="#System-config-in-master" class="headerlink" title="System config in master"></a>System config in master</h2><p>/work/hosts</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">root@192.168.4.210</span><br><span class="line">root@192.168.4.211</span><br><span class="line">root@192.168.4.212</span><br><span class="line">root@192.168.4.213</span><br><span class="line">root@192.168.4.214</span><br><span class="line">root@192.168.4.215</span><br><span class="line">root@192.168.4.216</span><br><span class="line">root@192.168.4.217</span><br></pre></td></tr></table></figure>

<p>/etc/hosts</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1       localhost</span><br><span class="line">127.0.1.1       ubuntu</span><br><span class="line"></span><br><span class="line"># The following lines are desirable for IPv6 capable hosts</span><br><span class="line">::1     localhost ip6-localhost ip6-loopback</span><br><span class="line">ff02::1 ip6-allnodes</span><br><span class="line">ff02::2 ip6-allrouters</span><br><span class="line"></span><br><span class="line">192.168.4.211 n1</span><br><span class="line">192.168.4.212 n2</span><br><span class="line">192.168.4.213 n3</span><br><span class="line">192.168.4.214 n4</span><br><span class="line">192.168.4.215 n5</span><br><span class="line">192.168.4.216 n6</span><br><span class="line">192.168.4.217 n7</span><br></pre></td></tr></table></figure>

<p>/etc/environment</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">LANGUAGE&#x3D;&quot;zh_CN:zh:en_US:en&quot;</span><br><span class="line">LANG&#x3D;zh_CN.GBK</span><br><span class="line">SPARK_HOME&#x3D;&#x2F;work&#x2F;spark</span><br><span class="line">SCALA_HOME&#x3D;&#x2F;opt&#x2F;scala</span><br><span class="line">JAVA_HOME&#x3D;&#x2F;opt&#x2F;java</span><br><span class="line">J2SDKDIR&#x3D;&#x2F;opt&#x2F;java</span><br><span class="line">J2REDIR&#x3D;&#x2F;opt&#x2F;java&#x2F;jre</span><br><span class="line">DERBY_HOME&#x3D;&#x2F;opt&#x2F;java&#x2F;db</span><br><span class="line">PATH&#x3D;&quot;&#x2F;usr&#x2F;local&#x2F;sbin:&#x2F;usr&#x2F;local&#x2F;bin:&#x2F;usr&#x2F;sbin:&#x2F;usr&#x2F;bin:&#x2F;sbin:&#x2F;bin:&#x2F;usr&#x2F;games:&#x2F;usr&#x2F;local&#x2F;games:&#x2F;opt&#x2F;java&#x2F;bin:&#x2F;opt&#x2F;scala&#x2F;bin:&#x2F;work&#x2F;spark&#x2F;bin&quot;</span><br><span class="line">CLASSPATH&#x3D;..:&#x2F;opt&#x2F;java&#x2F;lib:&#x2F;opt&#x2F;java&#x2F;jre&#x2F;lib:&#x2F;opt&#x2F;scala&#x2F;lib:&#x2F;work&#x2F;spark&#x2F;jars</span><br></pre></td></tr></table></figure>

<p>/work/spark/conf/spark-env.sh,update <code>ens3</code> to your network interface</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">export SPARK_LOCAL_IP=$(ifconfig ens3 | grep "inet addr:" | awk '&#123;print $2&#125;' | cut -c 6-)</span><br><span class="line">export SPARK_MASTER_HOST=n1</span><br><span class="line">export SPARK_MASTER_PORT=7077</span><br><span class="line">export SPARK_MASTER_WEBUI_PORT=8000</span><br><span class="line">export SPARK_HISTORY_OPTS="-Dspark.history.fs.logDirectory=/work/spark/logs-event"</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="built_in">export</span> SPARK_EXECUTOR_CORES=1</span></span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="built_in">export</span> SPARK_EXECUTOR_MEMORY=512M</span></span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="built_in">export</span> SPARK_WORKER_INSTANCES=4</span></span><br></pre></td></tr></table></figure>

<p>update_hostname.sh, update default hostname <code>ubuntu</code> to <code>n{machine ip last number}</code></p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">!/usr/bin/env bash</span></span><br><span class="line">NODE_LOCAL_IP=$(ifconfig ens3 | grep "inet addr:" | awk '&#123;print $2&#125;' | cut -c 6-)</span><br><span class="line">NEW_HOSTNAME="n$&#123;NODE_LOCAL_IP:12&#125;"</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="built_in">echo</span> <span class="variable">$NEW_HOSTNAME</span> &gt; /proc/sys/kernel/hostname</span></span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="built_in">echo</span> <span class="variable">$NEW_HOSTNAME</span> &gt; /etc/hostname</span></span><br><span class="line"></span><br><span class="line">sed -i 's/127.0.1.1.*/127.0.1.1\t'"$NEW_HOSTNAME"'/g' /etc/hosts</span><br><span class="line">hostnamectl set-hostname $NEW_HOSTNAME</span><br></pre></td></tr></table></figure>

<h2 id="Init-master-and-slaves-in-master"><a href="#Init-master-and-slaves-in-master" class="headerlink" title="Init master and slaves in master"></a>Init master and slaves in master</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line">pssh -h hosts "apt update"</span><br><span class="line">pssh -h hosts "apt install htop -y"</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">zsh init</span></span><br><span class="line">pssh -h hosts "apt install zsh -y"</span><br><span class="line">pssh -h hosts 'sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)";'</span><br><span class="line">pssh -h hosts chsh -s $(which zsh)</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">update dns resolve</span></span><br><span class="line">pscp -h hosts /etc/resolvconf/resolv.conf.d/base /etc/resolvconf/resolv.conf.d/base</span><br><span class="line">pssh -h hosts "resolvconf -u"</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">host update</span></span><br><span class="line">pscp -h hosts /etc/hosts /etc</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">create work directory</span></span><br><span class="line">pssh -h hosts "mkdir /work"</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">copy from master: 192.168.4.210</span></span><br><span class="line"><span class="meta">#</span><span class="bash">plesae remove 192.168.4.210 <span class="keyword">in</span> hosts</span></span><br><span class="line"></span><br><span class="line">tar -zxvf jdk-8u172-linux-x64.tar.gz -C /opt</span><br><span class="line">tar -zxvf scala-2.11.12.tgz -C /opt</span><br><span class="line">tar -zxvf scala-2.11.12.tgz -C /opt</span><br><span class="line">mv /opt/jdk-8u172-linux-x64 /opt/java</span><br><span class="line">mv /opt/scala-2.11.12 /opt/scala</span><br><span class="line"></span><br><span class="line">tar -zxvf spark-2.3.0-bin-hadoop2.7.tgz -C /work</span><br><span class="line">mv spark-2.3.0-bin-hadoop2.7 spark</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">copy java, scala</span></span><br><span class="line">pscp -r -h hosts /opt/* /opt/</span><br><span class="line"><span class="meta">#</span><span class="bash">copy spark</span></span><br><span class="line">pscp -r -h hosts /work/spark /work</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">update env variables</span></span><br><span class="line">pscp -h hosts /etc/environment /etc</span><br><span class="line">pssh -h hosts "source /etc/environment"</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">update hostname</span></span><br><span class="line">pscp -h hosts update_hostname.sh /tmp/</span><br><span class="line">pssh -h hosts "./tmp/update_hostname.sh"</span><br></pre></td></tr></table></figure>


<h2 id="Hadoop-config-in-master"><a href="#Hadoop-config-in-master" class="headerlink" title="Hadoop config in master"></a>Hadoop config in master</h2><p>此处引入<code>hadoop</code>是为了slaves从<code>hadoop</code>拉去资源启动app；</p>
<p>当然，也可以复制jar到各slaves相同的路径启动；</p>
<p>后面发现，每次重启app，spark都会从<code>hadoop</code>全量拉取一遍资源到<code>spark/work</code>目录。</p>
<p>core-site.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span></span><br><span class="line"><span class="meta">&lt;?xml-stylesheet type="text/xsl" href="configuration.xsl"?&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">name</span>&gt;</span>hadoop.tmp.dir<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">value</span>&gt;</span>file:/work/hadoop/tmp<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">description</span>&gt;</span>Abase for other temporary directories.<span class="tag">&lt;/<span class="name">description</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">name</span>&gt;</span>fs.defaultFS<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">value</span>&gt;</span>hdfs://n0:9820<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>hdfs-site.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span></span><br><span class="line"><span class="meta">&lt;?xml-stylesheet type="text/xsl" href="configuration.xsl"?&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.replication<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">value</span>&gt;</span>1<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.namenode.name.dir<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">value</span>&gt;</span>file:/work/hadoop/tmp/dfs/namenode<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.datanode.data.dir<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="name">value</span>&gt;</span>file:/work/hadoop/tmp/dfs/datanode<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.http.address<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>n0:9870<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.permissions.enabled<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>false<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.permissions.superusergroup<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>hadoop<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">name</span>&gt;</span>hadoop.http.staticuser.user<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>hadoop<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.secondary.http.address<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>n0:9868<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.datanode.http.address<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>n0:9864<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.datanode.address<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>n0:9866<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.datanode.hostname<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>n0<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>init <code>hadoop</code></p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">create hadoop user <span class="keyword">in</span> master</span></span><br><span class="line">sudo useradd -m hadoop -s /bin/bash</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">/work/hadoop/bin</span></span><br><span class="line">./hdfs dfs -mkdir -p /sparkHistoryLogs</span><br><span class="line">./hdfs dfs -mkdir -p /eventLogs</span><br><span class="line">./hdfs dfs -mkdir -p /spark</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">./hdfs dfs -rm -R /spark/app/*</span></span><br></pre></td></tr></table></figure>

<p>copy_app_resouces_to_hadoop.sh, run as <code>hadoop</code> user</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">!/bin/bash</span></span><br><span class="line">cd /work/hadoop/bin</span><br><span class="line"><span class="meta">#</span><span class="bash">./hdfs dfs -mkdir -p /spark</span></span><br><span class="line">./hdfs dfs -rm -R /spark/app/*</span><br><span class="line">./hdfs dfs -copyFromLocal -f /work/spark/app/log4j.properties /spark/app</span><br><span class="line"><span class="meta">#</span><span class="bash">spark config</span></span><br><span class="line">./hdfs dfs -copyFromLocal -f /work/spark/app/default.conf /spark/app</span><br><span class="line"><span class="meta">#</span><span class="bash">app dependencies</span></span><br><span class="line">./hdfs dfs -copyFromLocal -f /work/spark/app/lib /spark/app</span><br><span class="line">./hdfs dfs -copyFromLocal -f /work/spark/app/node-quality-streaming-0.0.1-SNAPSHOT.jar /spark/app</span><br></pre></td></tr></table></figure>

<h2 id="Exception-solutions"><a href="#Exception-solutions" class="headerlink" title="Exception solutions"></a>Exception solutions</h2><ul>
<li><p>fix spark WorkWebUI hostname(logs) 指向master机器hostname</p>
<p>看源码，在<code>spark-env.sh</code>中指定<code>SPARK_LOCAL_HOSTNAME</code>并没起作用，</p>
<p>解决方案：设置<code>SPARK_PUBLIC_DNS</code>参数后，worker webui中的跳转链接正常了。</p>
<p><code>SPARK_PUBLIC_DNS</code>→<code>publicHostName</code>我也是服了，</p>
<p>如下图，原先<code>stdout</code>的链接的的主机为<code>n0</code>，<code>n0</code>为master所在的机器：</p>
<img src="/2018/05/07/build-spark-cluster/spark-worker-ui-hostname.png" alt="spark-worker-ui-hostname.png" title="">

<p>源码参考</p>
<p><a href="https://github.com/apache/spark/blob/master/core/src/main/scala/org/apache/spark/ui/WebUI.scala" target="_blank" rel="noopener">core/src/main/scala/org/apache/spark/ui/WebUI.scala</a></p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">val</span> publicHostName = <span class="type">Option</span>(conf.getenv(<span class="string">"SPARK_PUBLIC_DNS"</span>)).getOrElse(</span><br><span class="line">    conf.get(<span class="type">DRIVER_HOST_ADDRESS</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment">/** Return the url of web interface. Only valid after bind(). */</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">webUrl</span></span>: <span class="type">String</span> = <span class="string">s"http://<span class="subst">$publicHostName</span>:<span class="subst">$boundPort</span>"</span></span><br></pre></td></tr></table></figure>

<p><a href="https://github.com/apache/spark/blob/master/core/src/main/scala/org/apache/spark/util/Utils.scala" target="_blank" rel="noopener">core/src/main/scala/org/apache/spark/util/Utils.scala</a></p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">lazy</span> <span class="keyword">val</span> localIpAddress: <span class="type">InetAddress</span> = findLocalInetAddress()</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">var</span> customHostname: <span class="type">Option</span>[<span class="type">String</span>] = sys.env.get(<span class="string">"SPARK_LOCAL_HOSTNAME"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Get the local machine's URI.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">localHostNameForURI</span></span>(): <span class="type">String</span> = &#123;</span><br><span class="line">  customHostname.getOrElse(<span class="type">InetAddresses</span>.toUriString(localIpAddress))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


</li>
</ul>
<ul>
<li><p>spark ConsumerRecord NotSerializableException bug</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">java.io.NotSerializableException: org.apache.kafka.clients.consumer.ConsumerRecord</span><br><span class="line">Serialization stack:</span><br><span class="line">    - <span class="function">object not <span class="title">serializable</span> <span class="params">(class: org.apache.kafka.clients.consumer.ConsumerRecord, value: ConsumerRecord(topic = hi2, partition = <span class="number">4</span>, offset = <span class="number">385</span>, CreateTime = <span class="number">1526369397516</span>, checksum = <span class="number">2122851237</span>, serialized key size = <span class="number">-1</span>, serialized value size = <span class="number">45</span>, key = <span class="keyword">null</span>, value = &#123;<span class="string">"date"</span>:<span class="number">1526369397516</span>,<span class="string">"message"</span>:<span class="string">"0hh2KcCH4j"</span>&#125;)</span>)</span></span><br><span class="line"><span class="function">    - element of <span class="title">array</span> <span class="params">(index: <span class="number">0</span>)</span></span></span><br><span class="line"><span class="function">    - <span class="title">array</span> <span class="params">(class [Lorg.apache.kafka.clients.consumer.ConsumerRecord;, size <span class="number">125</span>)</span></span></span><br><span class="line"><span class="function">    at org.apache.spark.serializer.SerializationDebugger$.<span class="title">improveException</span><span class="params">(SerializationDebugger.scala:<span class="number">40</span>)</span></span></span><br><span class="line"><span class="function">    at org.apache.spark.serializer.JavaSerializationStream.<span class="title">writeObject</span><span class="params">(JavaSerializer.scala:<span class="number">46</span>)</span></span></span><br><span class="line"><span class="function">    at org.apache.spark.serializer.JavaSerializerInstance.<span class="title">serialize</span><span class="params">(JavaSerializer.scala:<span class="number">100</span>)</span></span></span><br><span class="line"><span class="function">    at org.apache.spark.executor.Executor$TaskRunner.<span class="title">run</span><span class="params">(Executor.scala:<span class="number">393</span>)</span></span></span><br><span class="line"><span class="function">    at java.util.concurrent.ThreadPoolExecutor.<span class="title">runWorker</span><span class="params">(ThreadPoolExecutor.java:<span class="number">1149</span>)</span></span></span><br><span class="line"><span class="function">    at java.util.concurrent.ThreadPoolExecutor$Worker.<span class="title">run</span><span class="params">(ThreadPoolExecutor.java:<span class="number">624</span>)</span></span></span><br><span class="line"><span class="function">    at java.lang.Thread.<span class="title">run</span><span class="params">(Thread.java:<span class="number">748</span>)</span></span></span><br></pre></td></tr></table></figure>

<p>解决方案</p>
<p>set SparkConf</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sparkConf.set(<span class="string">"spark.serializer"</span>, <span class="string">"org.apache.spark.serializer.KryoSerializer"</span>);</span><br><span class="line">sparkConf.set(<span class="string">"spark.kryo.registrator"</span>, <span class="string">"me.codz.registrator.CunstomRegistrator"</span>);</span><br></pre></td></tr></table></figure>

<p>create CunstomRegistrator</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> me.codz.registrator;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.esotericsoftware.kryo.Kryo;</span><br><span class="line"><span class="keyword">import</span> org.apache.kafka.clients.consumer.ConsumerRecord;</span><br><span class="line"><span class="keyword">import</span> org.apache.spark.serializer.KryoRegistrator;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CunstomRegistrator</span> <span class="keyword">implements</span> <span class="title">KryoRegistrator</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerClasses</span><span class="params">(Kryo kryo)</span> </span>&#123;</span><br><span class="line">        kryo.register(ConsumerRecord<span class="class">.<span class="keyword">class</span>)</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>spark TaskContext.get() cause NullPointerException</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">stream.foreachRDD((VoidFunction2&lt;JavaRDD&lt;ConsumerRecord&lt;String, String&gt;&gt;, Time&gt;) (v1, v2) -&gt; &#123;</span><br><span class="line">           OffsetRange[] offsetRanges = ((HasOffsetRanges) v1.rdd()).offsetRanges();</span><br><span class="line"></span><br><span class="line">           List&lt;ConsumerRecord&lt;String, String&gt;&gt; consumerRecordList = CollectionTools.emptyWrapper(v1.collect());</span><br><span class="line">           consumerRecordList.forEach(consumerRecord -&gt; &#123;</span><br><span class="line">               TaskContext taskContext = TaskContext.get();</span><br><span class="line">               <span class="keyword">int</span> partitionId = taskContext.partitionId();</span><br><span class="line">               OffsetRange o = offsetRanges[partitionId];</span><br><span class="line"></span><br><span class="line">               <span class="comment">//...</span></span><br><span class="line">           &#125;);</span><br><span class="line"></span><br><span class="line">       &#125;);</span><br></pre></td></tr></table></figure>

<p>解决方案<br>using <code>foreachPartition</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">v1.foreachPartition(consumerRecordIterator -&gt; &#123;</span><br><span class="line">                <span class="keyword">while</span> (consumerRecordIterator.hasNext()) &#123;</span><br><span class="line">                    ConsumerRecord&lt;String, String&gt; consumerRecord = consumerRecordIterator.next();</span><br><span class="line"></span><br><span class="line">                    <span class="comment">//...</span></span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                TaskContext taskContext = TaskContext.get();</span><br><span class="line">                <span class="keyword">int</span> partitionId = taskContext.partitionId();</span><br><span class="line">                OffsetRange offsetRange = offsetRanges[partitionId];</span><br><span class="line"></span><br><span class="line">                <span class="comment">//...</span></span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;);</span><br></pre></td></tr></table></figure>
</li>
<li><p>Spark app connect kafka server by ip suspend</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">2018-06-07 18:40:16 [ForkJoinPool-1-worker-5] INFO :: [Consumer clientId&#x3D;consumer-1, groupId&#x3D;node-quality-streaming] Discovered group coordinator lau.cc:9092 (id: 2147483647 rack: null)</span><br><span class="line">2018-06-07 18:40:18 [ForkJoinPool-1-worker-5] INFO :: [Consumer clientId&#x3D;consumer-1, groupId&#x3D;node-quality-streaming] Group coordinator lau.cc:9092 (id: 2147483647 rack: null) is unavailable or invalid, will attempt rediscovery</span><br></pre></td></tr></table></figure>

<p>解决方案</p>
<p>vim kafka/config/server.properties</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">#add follow line</span><br><span class="line">advertised.host.name&#x3D;192.168.3.20</span><br></pre></td></tr></table></figure>

<p>kafka <code>advertised.host.name</code> DEPRECATED since 0.10.x, <a href="https://kafka.apache.org/0100/documentation.html#brokerconfigs" target="_blank" rel="noopener">0100 brokerconfigs</a></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DEPRECATED: only used when &#96;advertised.listeners&#96; or &#96;listeners&#96; are not set. Use &#96;advertised.listeners&#96; instead. Hostname to publish to ZooKeeper for clients to use. In IaaS environments, this may need to be different from the interface to which the broker binds. If this is not set, it will use the value for &#96;host.name&#96; if configured. Otherwise it will use the value returned from java.net.InetAddress.getCanonicalHostName().</span><br></pre></td></tr></table></figure>

<p>so follow config can also take effect</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">listeners&#x3D;PLAINTEXT:&#x2F;&#x2F;192.168.3.20:9092</span><br><span class="line">advertised.listeners&#x3D;PLAINTEXT:&#x2F;&#x2F;192.168.3.20:9092</span><br></pre></td></tr></table></figure>
</li>
<li><p>mark</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">java.lang.OutOfMemoryError: unable to create new native thread</span><br><span class="line"></span><br><span class="line">Offsets out of range with no configured reset policy for partitions</span><br></pre></td></tr></table></figure>

</li>
</ul>
<h2 id="Zookeeper-cluster-init"><a href="#Zookeeper-cluster-init" class="headerlink" title="Zookeeper cluster init"></a>Zookeeper cluster init</h2><p><a href="https://www.apache.org/dyn/closer.cgi/zookeeper/" target="_blank" rel="noopener">Download package from here</a></p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">tar -zxvf zookeeper-3.4.12.tar.gz -C /work</span><br><span class="line">mv zookeeper-3.4.12 zookeeper</span><br><span class="line"></span><br><span class="line">cp conf/zoo_sample.cfg conf/zoo.cfg</span><br></pre></td></tr></table></figure>

<p>vim conf/zoo.cfg</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">tickTime&#x3D;2000</span><br><span class="line">initLimit&#x3D;10</span><br><span class="line">syncLimit&#x3D;5</span><br><span class="line">dataDir&#x3D;&#x2F;work&#x2F;zookeeper&#x2F;data</span><br><span class="line">clientPort&#x3D;2181</span><br><span class="line"></span><br><span class="line">server.0&#x3D;192.168.4.210:2888:3888</span><br><span class="line">server.1&#x3D;192.168.4.211:2888:3888</span><br><span class="line">server.2&#x3D;192.168.4.212:2888:3888</span><br><span class="line">server.3&#x3D;192.168.4.213:2888:3888</span><br><span class="line">server.4&#x3D;192.168.4.214:2888:3888</span><br><span class="line">server.5&#x3D;192.168.4.215:2888:3888</span><br><span class="line">server.6&#x3D;192.168.4.216:2888:3888</span><br><span class="line">server.7&#x3D;192.168.4.217:2888:3888</span><br></pre></td></tr></table></figure>

<p>bin/init_myid.sh, update <code>ens3</code> to your network interface</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">!/bin/bash</span></span><br><span class="line">NODE_LOCAL_IP=$(ifconfig ens3 | grep "inet addr:" | awk '&#123;print $2&#125;' | cut -c 6-)</span><br><span class="line">echo $&#123;NODE_LOCAL_IP##*.&#125; &gt; /work/zookeeper/data/myid</span><br></pre></td></tr></table></figure>

<p>init cluster myid</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pssh -h /work/hosts "/work/zookeeper/bin/init_myid.sh"</span><br></pre></td></tr></table></figure>

<p>start zookeeper cluster</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pssh -h /work/hhosts -o out "/work/zookeeper/bin/zkServer.sh start"</span><br></pre></td></tr></table></figure>

<h2 id="参考内容"><a href="#参考内容" class="headerlink" title="参考内容"></a>参考内容</h2><ul>
<li><p><a href="https://code.google.com/archive/p/parallel-ssh/downloads" target="_blank" rel="noopener">parallel-ssh download page</a></p>
</li>
<li><p><a href="https://www.iteblog.com/archives/2270.html" target="_blank" rel="noopener">Hadoop 2.x Port &amp; 3.x 多个服务的默认端口被改变</a></p>
</li>
<li><p><a href="https://hadoop.apache.org/docs/r3.1.0/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml" target="_blank" rel="noopener">hadoop r3.1.0 hdfs-default.xml</a></p>
</li>
<li><p><a href="https://stackoverflow.com/questions/47310619/cant-delete-hdfs-directory-via-web-interface-because-im-dr-who" target="_blank" rel="noopener">Can’t Delete HDFS Directory Via Web Interface Because I’m Dr. Who</a></p>
</li>
<li><p><a href="https://github.com/apache/spark/pull/11490/commits/d64ade1939e51bfa4da0958e1057164b725ad7f3" target="_blank" rel="noopener">[SPARK-13117] [Web UI] WebUI should use the local ip not 0.0.0.0 #11490</a></p>
</li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://codz-me.vercel.app/2018/02/28/ssh-login-with-key-fail-and-require-password/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/head.png">
      <meta itemprop="name" content="laudukang">
      <meta itemprop="description" content="Bug Not Found">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Code Is Poetry">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2018/02/28/ssh-login-with-key-fail-and-require-password/" class="post-title-link" itemprop="url">用户目录权限问题导致 SSH 免密码登录失败</a>
        </h1>

        <div class="post-meta">
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2025-07-10 10:47:39 10:47:39" itemprop="dateModified" datetime="2025-07-10T10:47:39+08:00">2025-07-10 10:47:39</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Linux/" itemprop="url" rel="index">
                    <span itemprop="name">Linux</span>
                  </a>
                </span>
            </span>

          
            <span id="/2018/02/28/ssh-login-with-key-fail-and-require-password/" class="post-meta-item leancloud_visitors" data-flag-title="用户目录权限问题导致 SSH 免密码登录失败" title="阅读次数">
                <span hidden class="leancloud-visitors-count"></span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>正确配置了公钥到远程机器，并且 <code>/root/.ssh/authorized_keys</code>存在公钥</p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-copy-id -i ~/.ssh/id_rsa.pub <span class="symbol">root@</span><span class="number">192.168</span><span class="number">.3</span><span class="number">.20</span></span><br></pre></td></tr></table></figure>

<p>权限确认无误</p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">ls -al /root/.ssh</span><br><span class="line">total <span class="number">24</span></span><br><span class="line">drwxr-xr-x  <span class="number">2</span> root root <span class="number">4096</span> Nov <span class="number">13</span> <span class="number">16</span>:<span class="number">09</span> .</span><br><span class="line">drwx------ <span class="number">24</span> root root <span class="number">4096</span> Feb <span class="number">28</span> <span class="number">15</span>:<span class="number">16</span> ..</span><br><span class="line">-rw-------  <span class="number">1</span> root root  <span class="number">785</span> Oct  <span class="number">9</span> <span class="number">18</span>:<span class="number">23</span> authorized_keys</span><br><span class="line">-rw-------  <span class="number">1</span> root root <span class="number">1679</span> Jul <span class="number">29</span>  <span class="number">2017</span> id_rsa</span><br><span class="line">-rw-r--r--  <span class="number">1</span> root root  <span class="number">395</span> Jul <span class="number">29</span>  <span class="number">2017</span> id_rsa.pub</span><br><span class="line">-rw-r--r--  <span class="number">1</span> root root <span class="number">3548</span> Feb  <span class="number">7</span> <span class="number">18</span>:<span class="number">22</span> known_hosts</span><br></pre></td></tr></table></figure>

<p>然而登录还是需要输入密码，key不生效</p>
<p>最后查看log文件，发现很重要的一行<code>Authentication refused: bad ownership or modes for directory /root</code></p>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">vim /var/log/auth.log</span><br><span class="line"></span><br><span class="line">Feb 28 15:00:45 ubuntu sshd[6209]:<span class="built_in"> Connection </span>closed by 192.168.3.30<span class="built_in"> port </span>11364 [preauth]</span><br><span class="line">Feb 28 15:03:12 ubuntu sshd[6206]: Received signal 15; terminating.</span><br><span class="line">Feb 28 15:03:12 ubuntu sshd[6217]:<span class="built_in"> Server </span>listening on 0.0.0.0<span class="built_in"> port </span>22.</span><br><span class="line">Feb 28 15:03:12 ubuntu sshd[6217]:<span class="built_in"> Server </span>listening on ::<span class="built_in"> port </span>22.</span><br><span class="line">Feb 28 15:03:37 ubuntu sshd[6224]: Authentication refused: bad ownership <span class="keyword">or</span> modes <span class="keyword">for</span> directory /root</span><br><span class="line">Feb 28 15:03:37 ubuntu sshd[6224]: message repeated 3 times: [ Authentication refused: bad ownership <span class="keyword">or</span> modes <span class="keyword">for</span> directory /root]</span><br></pre></td></tr></table></figure>

<p><code>/root</code>的权限为</p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">drwxr-xr-x   <span class="number">6</span>  <span class="number">501</span> staff  <span class="number">4096</span> Feb <span class="number">28</span> <span class="number">15</span>:<span class="number">03</span> root/</span><br></pre></td></tr></table></figure>

<p>f*ck，系统是硬盘clone过来的，样本为啥要修改<code>/root</code>权限？！</p>
<p>最后修改<code>/root</code>权限为700完美解决！</p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://codz-me.vercel.app/2018/01/05/annual-book-list-2018/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/head.png">
      <meta itemprop="name" content="laudukang">
      <meta itemprop="description" content="Bug Not Found">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Code Is Poetry">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2018/01/05/annual-book-list-2018/" class="post-title-link" itemprop="url">2018我的书单</a>
        </h1>

        <div class="post-meta">
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2018-09-18 09:02:11 09:02:11" itemprop="dateModified" datetime="2018-09-18T09:02:11+08:00">2018-09-18 09:02:11</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Life/" itemprop="url" rel="index">
                    <span itemprop="name">Life</span>
                  </a>
                </span>
            </span>

          
            <span id="/2018/01/05/annual-book-list-2018/" class="post-meta-item leancloud_visitors" data-flag-title="2018我的书单" title="阅读次数">
                <span hidden class="leancloud-visitors-count"></span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <ul>
<li><p>一月</p>
<ul>
<li><a href="https://item.jd.com/11610470.html" target="_blank" rel="noopener">投资自己的梦想 孙正义的人生哲学</a></li>
</ul>
</li>
<li><p>三月</p>
<ul>
<li><a href="https://item.jd.com/11549140.html" target="_blank" rel="noopener">人类简史 从动物到上帝</a></li>
</ul>
</li>
<li><p>四月</p>
<ul>
<li><a href="https://item.jd.com/11354663.html" target="_blank" rel="noopener">Linux系统命令及Shell脚本实践指南</a></li>
</ul>
</li>
<li><p>五月</p>
<ul>
<li><a href="https://item.jd.com/11514065.html" target="_blank" rel="noopener">只是为了好玩 Linux之父林纳斯自传</a></li>
</ul>
</li>
<li><p>六月</p>
<ul>
<li><a href="https://item.jd.com/11967827.html" target="_blank" rel="noopener">所谓情商高，就是会说话</a></li>
</ul>
</li>
<li><p>八月</p>
<ul>
<li><a href="https://item.jd.com/12368811.html" target="_blank" rel="noopener">重来：更为简单有效的商业思维</a></li>
</ul>
</li>
<li><p>九月</p>
<ul>
<li><a href="https://item.jd.com/12425746.html" target="_blank" rel="noopener">Flink基础教程</a></li>
</ul>
</li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://codz-me.vercel.app/2017/12/20/recommend-articles/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/head.png">
      <meta itemprop="name" content="laudukang">
      <meta itemprop="description" content="Bug Not Found">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Code Is Poetry">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2017/12/20/recommend-articles/" class="post-title-link" itemprop="url">Recommend Articles</a>
        </h1>

        <div class="post-meta">
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2017-12-21 11:06:48 11:06:48" itemprop="dateModified" datetime="2017-12-21T11:06:48+08:00">2017-12-21 11:06:48</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/uncategorized/" itemprop="url" rel="index">
                    <span itemprop="name">uncategorized</span>
                  </a>
                </span>
            </span>

          
            <span id="/2017/12/20/recommend-articles/" class="post-meta-item leancloud_visitors" data-flag-title="Recommend Articles" title="阅读次数">
                <span hidden class="leancloud-visitors-count"></span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <ul>
<li><a href="http://www.gotw.ca/publications/concurrency-ddj.htm" target="_blank" rel="noopener">The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software</a></li>
<li><a href="http://dreamsongs.com/RiseOfWorseIsBetter.html" target="_blank" rel="noopener">The Rise of Worse is Better</a></li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://codz-me.vercel.app/2017/10/12/minio-and-nginx/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/head.png">
      <meta itemprop="name" content="laudukang">
      <meta itemprop="description" content="Bug Not Found">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Code Is Poetry">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2017/10/12/minio-and-nginx/" class="post-title-link" itemprop="url">High Vailability Minio Deploy Tutorial</a>
        </h1>

        <div class="post-meta">
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2017-10-12 19:06:44 19:06:44" itemprop="dateModified" datetime="2017-10-12T19:06:44+08:00">2017-10-12 19:06:44</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Linux/" itemprop="url" rel="index">
                    <span itemprop="name">Linux</span>
                  </a>
                </span>
            </span>

          
            <span id="/2017/10/12/minio-and-nginx/" class="post-meta-item leancloud_visitors" data-flag-title="High Vailability Minio Deploy Tutorial" title="阅读次数">
                <span hidden class="leancloud-visitors-count"></span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h2 id="Minio-Introduction"><a href="#Minio-Introduction" class="headerlink" title="Minio Introduction"></a><a href="https://minio.io/" target="_blank" rel="noopener">Minio Introduction</a></h2><p>Minio is an object storage server released under Apache License v2.0.</p>
<p>It is compatible with Amazon S3 cloud storage service.</p>
<p>It is best suited for storing unstructured data such as photos, videos, log files, backups and container / VM images.</p>
<p>Size of an object can range from a few KBs to a maximum of 5TB.</p>
<p>Minio server is light enough to be bundled with the application stack, similar to NodeJS, Redis and MySQL.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /tmp</span><br><span class="line"><span class="comment">#https://dl.minio.io/server/minio/release/中选择合适的版本</span></span><br><span class="line">curl -O https://dl.minio.io/server/minio/release/linux-amd64/minio</span><br><span class="line">sudo chmod +x minio</span><br><span class="line"><span class="comment">#directory where Minio's systemd startup script expects to find it</span></span><br><span class="line">sudo mv minio /usr/<span class="built_in">local</span>/bin</span><br><span class="line"></span><br><span class="line">sudo useradd -r minio-user -s /sbin/nologin</span><br><span class="line">sudo chown minio-user:minio-user /usr/<span class="built_in">local</span>/bin/minio</span><br><span class="line"></span><br><span class="line"><span class="comment">#创建数据存储目录</span></span><br><span class="line">sudo mkdir -p /work/minio/data1 /work/minio/data2</span><br><span class="line">sudo chown minio-user:minio-user /work/minio</span><br><span class="line"></span><br><span class="line"><span class="comment">#创建配置文件目录</span></span><br><span class="line">sudo mkdir /etc/minio</span><br><span class="line">sudo chown minio-user:minio-user /etc/minio</span><br><span class="line"></span><br><span class="line"><span class="comment">#default config, modify your own MINIO_VOLUMES/MINIO_OPTS/MINIO_ACCESS_KEY/MINIO_SECRET_KEY</span></span><br><span class="line">cat &lt;&lt;EOF &gt; /etc/default/minio</span><br><span class="line"><span class="comment"># Remote node configuration.</span></span><br><span class="line">MINIO_VOLUMES=<span class="string">"http://192.168.3.21/work/minio/data1 http://192.168.3.21/work/minio/data2 http://192.168.3.23/work/minio/data1 http://192.168.3.23/work/minio/data2"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Use if you want to run Minio on a custom port.</span></span><br><span class="line">MINIO_OPTS=<span class="string">"-C /etc/minio --address :9001"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Access Key of the server.</span></span><br><span class="line">MINIO_ACCESS_KEY=YOUR-ACCESS-KEY-HERE</span><br><span class="line"></span><br><span class="line"><span class="comment"># Secret key of the server.</span></span><br><span class="line">MINIO_SECRET_KEY=YOUR-SECRET-KEY-HERE</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="built_in">cd</span> /etc/systemd/system/</span><br><span class="line">curl -O https://raw.githubusercontent.com/minio/minio-service/master/linux-systemd/distributed/minio.service</span><br><span class="line">sudo chmod 755 minio.service</span><br><span class="line">sudo systemctl daemon-reload</span><br><span class="line">sudo systemctl <span class="built_in">enable</span> minio</span><br><span class="line">sudo systemctl start minio</span><br><span class="line">sudo systemctl status minio</span><br></pre></td></tr></table></figure>

<h2 id="Nginx-Configuration"><a href="#Nginx-Configuration" class="headerlink" title="Nginx Configuration"></a>Nginx Configuration</h2><p>Multiple Minio servers load balance</p>
<figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">upstream</span> minio_servers &#123;</span><br><span class="line">    <span class="attribute">server</span> minio-server-<span class="number">1</span>:<span class="number">9000</span>;</span><br><span class="line">    <span class="attribute">server</span> minio-server-<span class="number">2</span>:<span class="number">9000</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span> <span class="number">80</span>;</span><br><span class="line">    <span class="attribute">server_name</span> www.example.com;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">location</span> / &#123;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Host <span class="variable">$http_host</span>;</span><br><span class="line">        <span class="attribute">proxy_pass</span>       http://minio_servers;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>SSL/TLS Termination</p>
<figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span> <span class="number">80</span>;</span><br><span class="line">    <span class="attribute">server_name</span> www.example.com;</span><br><span class="line">    <span class="attribute">return</span> <span class="number">301</span> https://www.example.com<span class="variable">$request_uri</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span>              <span class="number">443</span> ssl;</span><br><span class="line">    <span class="attribute">server_name</span>         www.example.com;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">ssl_certificate</span>     www.example.com.crt;</span><br><span class="line">    <span class="attribute">ssl_certificate_key</span> www.example.com.key;</span><br><span class="line">    <span class="attribute">ssl_protocols</span>       TLSv1 TLSv1.<span class="number">1</span> TLSv1.<span class="number">2</span>;</span><br><span class="line">    <span class="attribute">ssl_ciphers</span>         HIGH:!aNULL:!MD5;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">location</span> / &#123;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Host <span class="variable">$http_host</span>;</span><br><span class="line">        <span class="attribute">proxy_pass</span>       http://localhost:9000;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Nginx caching</p>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">limit_req_zone <span class="variable">$binary_remote_addr</span> <span class="attribute">zone</span>=my_req_limit:10m <span class="attribute">rate</span>=10r/s;</span><br><span class="line"></span><br><span class="line">server &#123;</span><br><span class="line">    # <span class="built_in">..</span>.</span><br><span class="line">    location /images/ &#123;</span><br><span class="line">        limit_req <span class="attribute">zone</span>=my_req_limit <span class="attribute">burst</span>=20;</span><br><span class="line">        # <span class="built_in">..</span>.</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ul>
<li><a href="https://github.com/minio/minio/tree/master/docs/distributed" target="_blank" rel="noopener">Distributed Minio Quickstart Guide</a></li>
<li><a href="https://github.com/minio/minio-service/tree/master/linux-systemd" target="_blank" rel="noopener">Systemd service for Minio</a></li>
<li><a href="https://www.nginx.com/blog/enterprise-grade-cloud-storage-nginx-plus-minio/" target="_blank" rel="noopener">Enterprise-Grade Cloud Storage with NGINX Plus and Minio</a></li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://codz-me.vercel.app/2017/09/24/rise-of-worse-is-better/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/head.png">
      <meta itemprop="name" content="laudukang">
      <meta itemprop="description" content="Bug Not Found">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Code Is Poetry">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2017/09/24/rise-of-worse-is-better/" class="post-title-link" itemprop="url">[Repost]The Rise of Worse is Better</a>
        </h1>

        <div class="post-meta">
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2017-09-24 16:57:21 16:57:21" itemprop="dateModified" datetime="2017-09-24T16:57:21+08:00">2017-09-24 16:57:21</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/uncategorized/" itemprop="url" rel="index">
                    <span itemprop="name">uncategorized</span>
                  </a>
                </span>
            </span>

          
            <span id="/2017/09/24/rise-of-worse-is-better/" class="post-meta-item leancloud_visitors" data-flag-title="[Repost]The Rise of Worse is Better" title="阅读次数">
                <span hidden class="leancloud-visitors-count"></span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>{an excerpt from “Lisp: Good News, Bad News, How to Win Big.” [html]}</p>
<p>2.1 The Rise of Worse is Better</p>
<p>I and just about every designer of Common Lisp and CLOS has had extreme exposure to the MIT/Stanford style of design. The essence of this style can be captured by the phrase the right thing. To such a designer it is important to get all of the following characteristics right:</p>
<p>Simplicity – the design must be simple, both in implementation and interface. It is more important for the interface to be simple than the implementation.<br>Correctness – the design must be correct in all observable aspects. Incorrectness is simply not allowed.<br>Consistency – the design must not be inconsistent. A design is allowed to be slightly less simple and less complete to avoid inconsistency. Consistency is as important as correctness.<br>Completeness – the design must cover as many important situations as is practical. All reasonably expected cases must be covered. Simplicity is not allowed to overly reduce completeness.<br>I believe most people would agree that these are good characteristics. I will call the use of this philosophy of design the MIT approach Common Lisp (with CLOS) and Scheme represent the MIT approach to design and implementation.</p>
<p>The worse-is-better philosophy is only slightly different:</p>
<p>Simplicity – the design must be simple, both in implementation and interface. It is more important for the implementation to be simple than the interface. Simplicity is the most important consideration in a design.<br>Correctness – the design must be correct in all observable aspects. It is slightly better to be simple than correct.<br>Consistency – the design must not be overly inconsistent. Consistency can be sacrificed for simplicity in some cases, but it is better to drop those parts of the design that deal with less common circumstances than to introduce either implementational complexity or inconsistency.<br>Completeness – the design must cover as many important situations as is practical. All reasonably expected cases should be covered. Completeness can be sacrificed in favor of any other quality. In fact, completeness must be sacrificed whenever implementation simplicity is jeopardized. Consistency can be sacrificed to achieve completeness if simplicity is retained; especially worthless is consistency of interface.<br>Early Unix and C are examples of the use of this school of design, and I will call the use of this design strategy the New Jersey approach I have intentionally caricatured the worse-is-better philosophy to convince you that it is obviously a bad philosophy and that the New Jersey approach is a bad approach.</p>
<p>However, I believe that worse-is-better, even in its strawman form, has better survival characteristics than the-right-thing, and that the New Jersey approach when used for software is a better approach than the MIT approach.</p>
<p>Let me start out by retelling a story that shows that the MIT/New-Jersey distinction is valid and that proponents of each philosophy actually believe their philosophy is better.</p>
<p>Two famous people, one from MIT and another from Berkeley (but working on Unix) once met to discuss operating system issues. The person from MIT was knowledgeable about ITS (the MIT AI Lab operating system) and had been reading the Unix sources. He was interested in how Unix solved the PC loser-ing problem. The PC loser-ing problem occurs when a user program invokes a system routine to perform a lengthy operation that might have significant state, such as IO buffers. If an interrupt occurs during the operation, the state of the user program must be saved. Because the invocation of the system routine is usually a single instruction, the PC of the user program does not adequately capture the state of the process. The system routine must either back out or press forward. The right thing is to back out and restore the user program PC to the instruction that invoked the system routine so that resumption of the user program after the interrupt, for example, re-enters the system routine. It is called PC loser-ing because the PC is being coerced into loser mode, where loser is the affectionate name for user at MIT.</p>
<p>The MIT guy did not see any code that handled this case and asked the New Jersey guy how the problem was handled. The New Jersey guy said that the Unix folks were aware of the problem, but the solution was for the system routine to always finish, but sometimes an error code would be returned that signaled that the system routine had failed to complete its action. A correct user program, then, had to check the error code to determine whether to simply try the system routine again. The MIT guy did not like this solution because it was not the right thing.</p>
<p>The New Jersey guy said that the Unix solution was right because the design philosophy of Unix was simplicity and that the right thing was too complex. Besides, programmers could easily insert this extra test and loop. The MIT guy pointed out that the implementation was simple but the interface to the functionality was complex. The New Jersey guy said that the right tradeoff has been selected in Unix – namely, implementation simplicity was more important than interface simplicity.</p>
<p>The MIT guy then muttered that sometimes it takes a tough man to make a tender chicken, but the New Jersey guy didn’t understand (I’m not sure I do either).</p>
<p>Now I want to argue that worse-is-better is better. C is a programming language designed for writing Unix, and it was designed using the New Jersey approach. C is therefore a language for which it is easy to write a decent compiler, and it requires the programmer to write text that is easy for the compiler to interpret. Some have called C a fancy assembly language. Both early Unix and C compilers had simple structures, are easy to port, require few machine resources to run, and provide about 50%-80% of what you want from an operating system and programming language.</p>
<p>Half the computers that exist at any point are worse than median (smaller or slower). Unix and C work fine on them. The worse-is-better philosophy means that implementation simplicity has highest priority, which means Unix and C are easy to port on such machines. Therefore, one expects that if the 50% functionality Unix and C support is satisfactory, they will start to appear everywhere. And they have, haven’t they?</p>
<p>Unix and C are the ultimate computer viruses.</p>
<p>A further benefit of the worse-is-better philosophy is that the programmer is conditioned to sacrifice some safety, convenience, and hassle to get good performance and modest resource use. Programs written using the New Jersey approach will work well both in small machines and large ones, and the code will be portable because it is written on top of a virus.</p>
<p>It is important to remember that the initial virus has to be basically good. If so, the viral spread is assured as long as it is portable. Once the virus has spread, there will be pressure to improve it, possibly by increasing its functionality closer to 90%, but users have already been conditioned to accept worse than the right thing. Therefore, the worse-is-better software first will gain acceptance, second will condition its users to expect less, and third will be improved to a point that is almost the right thing. In concrete terms, even though Lisp compilers in 1987 were about as good as C compilers, there are many more compiler experts who want to make C compilers better than want to make Lisp compilers better.</p>
<p>The good news is that in 1995 we will have a good operating system and programming language; the bad news is that they will be Unix and C++.</p>
<p>There is a final benefit to worse-is-better. Because a New Jersey language and system are not really powerful enough to build complex monolithic software, large systems must be designed to reuse components. Therefore, a tradition of integration springs up.</p>
<p>How does the right thing stack up? There are two basic scenarios: the big complex system scenario and the diamond-like jewel scenario.</p>
<p>The big complex system scenario goes like this:</p>
<p>First, the right thing needs to be designed. Then its implementation needs to be designed. Finally it is implemented. Because it is the right thing, it has nearly 100% of desired functionality, and implementation simplicity was never a concern so it takes a long time to implement. It is large and complex. It requires complex tools to use properly. The last 20% takes 80% of the effort, and so the right thing takes a long time to get out, and it only runs satisfactorily on the most sophisticated hardware.</p>
<p>The diamond-like jewel scenario goes like this:</p>
<p>The right thing takes forever to design, but it is quite small at every point along the way. To implement it to run fast is either impossible or beyond the capabilities of most implementors.</p>
<p>The two scenarios correspond to Common Lisp and Scheme.</p>
<p>The first scenario is also the scenario for classic artificial intelligence software.</p>
<p>The right thing is frequently a monolithic piece of software, but for no reason other than that the right thing is often designed monolithically. That is, this characteristic is a happenstance.</p>
<p>The lesson to be learned from this is that it is often undesirable to go for the right thing first. It is better to get half of the right thing available so that it spreads like a virus. Once people are hooked on it, take the time to improve it to 90% of the right thing.</p>
<p>A wrong lesson is to take the parable literally and to conclude that C is the right vehicle for AI software. The 50% solution has to be basically right, and in this case it isn’t.</p>
<p>But, one can conclude only that the Lisp community needs to seriously rethink its position on Lisp design. I will say more about this later….</p>
<h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ul>
<li><a href="http://dreamsongs.com/RiseOfWorseIsBetter.html" target="_blank" rel="noopener">The Rise of Worse is Better</a></li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://codz-me.vercel.app/2017/06/10/can-not-read-from-dev-random/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/head.png">
      <meta itemprop="name" content="laudukang">
      <meta itemprop="description" content="Bug Not Found">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Code Is Poetry">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2017/06/10/can-not-read-from-dev-random/" class="post-title-link" itemprop="url">Cannot read from /dev/random: Resource temporarily unavailable</a>
        </h1>

        <div class="post-meta">
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2017-06-10 16:51:32 16:51:32" itemprop="dateModified" datetime="2017-06-10T16:51:32+08:00">2017-06-10 16:51:32</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Linux/" itemprop="url" rel="index">
                    <span itemprop="name">Linux</span>
                  </a>
                </span>
            </span>

          
            <span id="/2017/06/10/can-not-read-from-dev-random/" class="post-meta-item leancloud_visitors" data-flag-title="Cannot read from /dev/random: Resource temporarily unavailable" title="阅读次数">
                <span hidden class="leancloud-visitors-count"></span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>issue</p>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Configuration file: /etc/hostapd/hostapd.conf</span><br><span class="line">Using<span class="built_in"> interface </span>wlp4s0 with hwaddr 3c:33:00:f6:67:2b <span class="keyword">and</span> ssid <span class="string">"Codz"</span></span><br><span class="line">random: Cannot read <span class="keyword">from</span> /dev/random:<span class="built_in"> Resource </span>temporarily unavailable</span><br><span class="line">random: Only 0/20 bytes of strong random data available <span class="keyword">from</span> /dev/random</span><br><span class="line">random: <span class="keyword">Not</span> enough entropy<span class="built_in"> pool </span>available <span class="keyword">for</span> secure operations</span><br><span class="line">WPA: <span class="keyword">Not</span> enough entropy <span class="keyword">in</span> random<span class="built_in"> pool </span><span class="keyword">for</span> secure operations - update keys later when the first station connects</span><br><span class="line">wlp4s0:<span class="built_in"> interface </span>state UNINITIALIZED-&gt;ENABLED</span><br><span class="line">wlp4s0: AP-ENABLED</span><br></pre></td></tr></table></figure>

<p>solution</p>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mv <span class="regexp">/dev/</span>random <span class="regexp">/dev/</span>random.orig</span><br><span class="line">ln -s <span class="regexp">/dev/u</span>random <span class="regexp">/dev/</span>random</span><br></pre></td></tr></table></figure>

<p>reference:</p>
<ul>
<li><a href="https://forum.openwrt.org/viewtopic.php?id=30931" target="_blank" rel="noopener">WPA Enterprise not working after upgrading to rc5</a></li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://codz-me.vercel.app/2017/02/19/annual-book-list-2017/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/head.png">
      <meta itemprop="name" content="laudukang">
      <meta itemprop="description" content="Bug Not Found">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Code Is Poetry">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2017/02/19/annual-book-list-2017/" class="post-title-link" itemprop="url">2017我的书单</a>
        </h1>

        <div class="post-meta">
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2017-12-22 15:57:44 15:57:44" itemprop="dateModified" datetime="2017-12-22T15:57:44+08:00">2017-12-22 15:57:44</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Life/" itemprop="url" rel="index">
                    <span itemprop="name">Life</span>
                  </a>
                </span>
            </span>

          
            <span id="/2017/02/19/annual-book-list-2017/" class="post-meta-item leancloud_visitors" data-flag-title="2017我的书单" title="阅读次数">
                <span hidden class="leancloud-visitors-count"></span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <ul>
<li>一月<ul>
<li><a href="https://item.jd.com/11398297.html" target="_blank" rel="noopener">MacTalk人生元编程</a></li>
<li><a href="https://item.jd.com/11803342.html" target="_blank" rel="noopener">MacTalk跨边界编程</a></li>
<li><a href="https://item.jd.com/11917790.html" target="_blank" rel="noopener">Java 8实战</a></li>
</ul>
</li>
<li>二月<ul>
<li><a href="https://item.jd.com/11322972.html" target="_blank" rel="noopener">大型网站技术架构 核心原理与案例分析</a></li>
<li><a href="https://www.amazon.cn/gp/product/B018QQZYTQ" target="_blank" rel="noopener">天才在左疯子在右(完整版)</a>(2.10-?)</li>
<li><a href="https://item.jd.com/11264057.html" target="_blank" rel="noopener">源泉-安·兰德</a>(2.19-12.22)</li>
<li><a href="https://item.jd.com/11458318.html" target="_blank" rel="noopener">程序员的呐喊</a>(2.20-?)</li>
</ul>
</li>
<li>三月<ul>
<li><a href="http://item.jd.com/11857434.html" target="_blank" rel="noopener">深入理解ElasticSearch</a></li>
<li><a href="http://item.jd.com/11988131.html" target="_blank" rel="noopener">科技之巅</a></li>
<li><a href="http://www.infoq.com/cn/minibooks/insighting-into-data" target="_blank" rel="noopener">洞见数据之密</a></li>
<li><a href="http://www.infoq.com/cn/minibooks/Microservice-DevOps" target="_blank" rel="noopener">架构师特刊：微服务与DevOps技术内参</a></li>
<li><a href="http://www.infoq.com/cn/minibooks/architect-201702" target="_blank" rel="noopener">架构师（2017年2月）</a></li>
<li><a href="https://www.amazon.cn/gp/product/B01N7EVWOH/" target="_blank" rel="noopener">图解设计模式</a></li>
</ul>
</li>
<li>四月<ul>
<li><a href="https://item.jd.com/10898799.html" target="_blank" rel="noopener">编写高质量代码：改善Java程序的151个建议</a></li>
<li><a href="https://item.jd.com/11763016.html" target="_blank" rel="noopener">Spark机器学习</a></li>
<li><a href="http://www.infoq.com/cn/minibooks/architect-201703" target="_blank" rel="noopener">架构师（2017年3月）</a></li>
</ul>
</li>
<li>五月<ul>
<li><a href="https://item.jd.com/11969881.html" target="_blank" rel="noopener">Spring Boot实战</a></li>
</ul>
</li>
<li>六月<ul>
<li><a href="http://www.infoq.com/cn/minibooks/architect-201704" target="_blank" rel="noopener">架构师（2017年4月）</a></li>
</ul>
</li>
<li>八月<ul>
<li><a href="https://item.jd.com/11749340.html" target="_blank" rel="noopener">重新定义公司：谷歌是如何运营的</a>(8.16-?)</li>
<li><a href="https://item.jd.com/12172344.html" target="_blank" rel="noopener">Spring Cloud微服务实战</a>(8.26-?)</li>
</ul>
</li>
<li>九月<ul>
<li><a href="https://item.jd.com/12013041.html" target="_blank" rel="noopener">Docker实战</a></li>
</ul>
</li>
<li>十月<ul>
<li><a href="https://item.jd.com/10582495.html" target="_blank" rel="noopener">黑客与画家：硅谷创业之父Paul Graham文集</a>(10.22-11.25)</li>
</ul>
</li>
<li>十二月<ul>
<li><a href="https://item.jd.com/11987407.html" target="_blank" rel="noopener">Spark Cookbook</a></li>
</ul>
</li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

        
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block home" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://codz-me.vercel.app/2017/01/14/a-bug-of-ubuntu-16_04_1/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/head.png">
      <meta itemprop="name" content="laudukang">
      <meta itemprop="description" content="Bug Not Found">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Code Is Poetry">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          
            <a href="/2017/01/14/a-bug-of-ubuntu-16_04_1/" class="post-title-link" itemprop="url">A bug of Ubuntu 16.04.1 LTS</a>
        </h1>

        <div class="post-meta">
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2017-02-22 21:05:29 21:05:29" itemprop="dateModified" datetime="2017-02-22T21:05:29+08:00">2017-02-22 21:05:29</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Linux/" itemprop="url" rel="index">
                    <span itemprop="name">Linux</span>
                  </a>
                </span>
            </span>

          
            <span id="/2017/01/14/a-bug-of-ubuntu-16_04_1/" class="post-meta-item leancloud_visitors" data-flag-title="A bug of Ubuntu 16.04.1 LTS" title="阅读次数">
                <span hidden class="leancloud-visitors-count"></span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>执行下面查询会报一堆错误</p>
<figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">root<span class="variable">@vagrant</span><span class="symbol">:/tmp</span><span class="comment">#find / -name "my.cnf"</span></span><br></pre></td></tr></table></figure>

<p>issue</p>
<figure class="highlight golo"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/devices.deny': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/init.scope/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/init.scope/devices.deny': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/devices.deny': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/vagrant.mount/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/vagrant.mount/devices.deny': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/mdadm.service/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/mdadm.service/devices.deny': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/vboxadd-x11.service/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/vboxadd-x11.service/devices.deny': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/ifup<span class="meta">@enp</span>0s8.service/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/ifup<span class="meta">@enp</span>0s8.service/devices.deny': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/boot.mount/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/boot.mount/devices.deny': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/dbus.service/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/dbus.service/devices.deny': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/<span class="keyword">var</span>-lib-lxcfs.mount/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/<span class="keyword">var</span>-lib-lxcfs.mount/devices.deny': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/cron.service/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/cron.service/devices.deny': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/run-user<span class="number">-0.</span>mount/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/run-user<span class="number">-0.</span>mount/devices.deny': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/lvm2-lvmetad.service/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/lvm2-lvmetad.service/devices.deny': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/run-lxcfs-controllers-cpu\\x2ccpuacct.mount/devices.allow': Permission denied <span class="keyword">find</span>: '/<span class="keyword">var</span>/lib/lxcfs/cgroup/devices/system.slice/run-lxcfs-controllers-cpu\\x2ccpuacct.mount/devices.deny': Permission denied</span><br></pre></td></tr></table></figure>

<p>版本信息</p>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">root@vagrant:/tmp# cat /etc/\*-release</span><br><span class="line"><span class="attribute">DISTRIB_ID</span>=Ubuntu</span><br><span class="line"><span class="attribute">DISTRIB_RELEASE</span>=16.04</span><br><span class="line"><span class="attribute">DISTRIB_CODENAME</span>=xenial</span><br><span class="line"><span class="attribute">DISTRIB_DESCRIPTION</span>=<span class="string">"Ubuntu 16.04.1 LTS"</span></span><br><span class="line"><span class="attribute">NAME</span>=<span class="string">"Ubuntu"</span></span><br><span class="line"><span class="attribute">VERSION</span>=<span class="string">"16.04.1 LTS (Xenial Xerus)"</span></span><br><span class="line"><span class="attribute">ID</span>=ubuntu</span><br><span class="line"><span class="attribute">ID_LIKE</span>=debian</span><br><span class="line"><span class="attribute">PRETTY_NAME</span>=<span class="string">"Ubuntu 16.04.1 LTS"</span></span><br><span class="line"><span class="attribute">VERSION_ID</span>=<span class="string">"16.04"</span></span><br><span class="line"><span class="attribute">HOME_URL</span>=<span class="string">"http://www.ubuntu.com/"</span></span><br><span class="line"><span class="attribute">SUPPORT_URL</span>=<span class="string">"http://help.ubuntu.com/"</span></span><br><span class="line"><span class="attribute">BUG_REPORT_URL</span>=<span class="string">"http://bugs.launchpad.net/ubuntu/"</span></span><br><span class="line"><span class="attribute">UBUNTU_CODENAME</span>=xenial</span><br></pre></td></tr></table></figure>

<blockquote><p>Bug was fix in lxcfs (2.0.4-0ubuntu1<del>ubuntu16.04.1)<br>debian/changelog :lxcfs (2.0.4-0ubuntu1</del>ubuntu16.04.1) xenial; urgency=medium</p>
<footer><strong>Bug #1656309</strong><cite><a href="https://bugs.launchpad.net/ubuntu/+source/lxcfs/+bug/1656309" target="_blank" rel="noopener">bugs.launchpad.net/ubuntu/+source/lxcfs/+bug/1656309</a></cite></footer></blockquote>

<br>
一个临时解决方案
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get remove --auto-remove lxcfs</span><br></pre></td></tr></table></figure>

<h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ul>
<li><a href="https://www.howtoinstall.co/en/ubuntu/xenial/lxcfs?action=remove" target="_blank" rel="noopener">How to remove lxcfs from Ubuntu 16.04 (Xenial Xerus)</a></li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

  </div>

  
  <nav class="pagination">
    <span class="page-number current">1</span><a class="page-number" href="/page/2/">2</a><span class="space">&hellip;</span><a class="page-number" href="/page/7/">7</a><a class="extend next" rel="next" href="/page/2/"><i class="fa fa-angle-right" aria-label="下一页"></i></a>
  </nav>



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let activeClass = CONFIG.comments.activeClass;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="laudukang"
      src="/images/head.png">
  <p class="site-author-name" itemprop="name">laudukang</p>
  <div class="site-description" itemprop="description">Bug Not Found</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">68</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">10</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">25</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/laudukang" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;laudukang" rel="noopener" target="_blank"><i class="fa fa-fw fa-github"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://gitee.com/laudukang" title="Gitee → https:&#x2F;&#x2F;gitee.com&#x2F;laudukang" rel="noopener" target="_blank"><i class="fa fa-fw fa-github-alt"></i>Gitee</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://stackoverflow.com/users/5621049/laudukang" title="StackOverflow → https:&#x2F;&#x2F;stackoverflow.com&#x2F;users&#x2F;5621049&#x2F;laudukang" rel="noopener" target="_blank"><i class="fa fa-fw fa-stack-overflow"></i>StackOverflow</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://www.google.com/maps/place/%E6%B7%B1%E5%9C%B3%E5%B8%82%E8%BD%AF%E4%BB%B6%E4%BA%A7%E4%B8%9A%E5%9F%BA%E5%9C%B0/@22.5244896,113.9382973,17z/data=!3m1!4b1!4m5!3m4!1s0x3403ee17d008a019:0xbb7b06b73d856c14!8m2!3d22.5244896!4d113.9382973" title="Map → https:&#x2F;&#x2F;www.google.com&#x2F;maps&#x2F;place&#x2F;%E6%B7%B1%E5%9C%B3%E5%B8%82%E8%BD%AF%E4%BB%B6%E4%BA%A7%E4%B8%9A%E5%9F%BA%E5%9C%B0&#x2F;@22.5244896,113.9382973,17z&#x2F;data&#x3D;!3m1!4b1!4m5!3m4!1s0x3403ee17d008a019:0xbb7b06b73d856c14!8m2!3d22.5244896!4d113.9382973" rel="noopener" target="_blank"><i class="fa fa-fw fa-map-marker"></i>Map</a>
      </span>
  </div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

<div class="copyright">
  
  &copy; 2015 – 
  <span itemprop="copyrightYear">2025</span>
  <span class="with-love">
    <i class="fa fa-heart icon-next-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">laudukang</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> 强力驱动 v4.2.0
  </div>
  <span class="post-meta-divider">|</span>
  <div class="theme-info">主题 – <a href="https://muse.theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Muse</a> v7.7.1
  </div>

        
<div class="busuanzi-count">
  <script pjax async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
</div>






  <script pjax>
  function leancloudSelector(url) {
    url = encodeURI(url);
    return document.getElementById(url).querySelector('.leancloud-visitors-count');
  }
  if (CONFIG.page.isPost) {
    function addCount(Counter) {
      var visitors = document.querySelector('.leancloud_visitors');
      var url = decodeURI(visitors.getAttribute('id'));
      var title = visitors.getAttribute('data-flag-title');

      Counter('get', `/classes/Counter?where=${JSON.stringify({ url })}`)
        .then(response => response.json())
        .then(({ results }) => {
          if (results.length > 0) {
            var counter = results[0];
              leancloudSelector(url).innerText = counter.time + 1;
            Counter('put', '/classes/Counter/' + counter.objectId, { time: { '__op': 'Increment', 'amount': 1 } })
              .then(response => response.json())
              .catch(error => {
                console.error('Failed to save visitor count', error);
              })
          } else {
              Counter('post', '/classes/Counter', { title: title, url: url, time: 1 })
                .then(response => response.json())
                .then(() => {
                  leancloudSelector(url).innerText = 1;
                })
                .catch(error => {
                  console.error('Failed to create', error);
                });
          }
        })
        .catch(error => {
          console.error('LeanCloud Counter Error', error);
        });
    }
  } else {
    function showTime(Counter) {
      var visitors = document.querySelectorAll('.leancloud_visitors');
      var entries = [...visitors].map(element => {
        return decodeURI(element.getAttribute('id'));
      });

      Counter('get', `/classes/Counter?where=${JSON.stringify({ url: { '$in': entries } })}`)
        .then(response => response.json())
        .then(({ results }) => {
          if (results.length === 0) {
            document.querySelectorAll('.leancloud_visitors .leancloud-visitors-count').forEach(element => {
              element.innerText = 0;
            });
            return;
          }
          for (let item of results) {
            let { url, time } = item;
            leancloudSelector(url).innerText = time;
          }
          for (let url of entries) {
            var element = leancloudSelector(url);
            if (element.innerText == '') {
              element.innerText = 0;
            }
          }
        })
        .catch(error => {
          console.error('LeanCloud Counter Error', error);
        });
    }
  }

  fetch('https://app-router.leancloud.cn/2/route?appId=CPfRDhOlTyfkHW155W3Kx3H1-gzGzoHsz')
    .then(response => response.json())
    .then(({ api_server }) => {
      var Counter = (method, url, data) => {
        return fetch(`https://${api_server}/1.1${url}`, {
          method: method,
          headers: {
            'X-LC-Id': 'CPfRDhOlTyfkHW155W3Kx3H1-gzGzoHsz',
            'X-LC-Key': 'TX05RQSQMd8fbL7RaJNADS7S',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data)
        });
      };
      if (CONFIG.page.isPost) {
        if (CONFIG.hostname !== location.hostname) return;
        addCount(Counter);
      } else if (document.querySelectorAll('.post-title-link').length >= 1) {
        showTime(Counter);
      }
    });
  </script>


      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/pjax/pjax.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js"></script>
  <script src="//cdn.jsdelivr.net/gh/fancyapps/fancybox@3/dist/jquery.fancybox.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/muse.js"></script>


<script src="/js/next-boot.js"></script>

  <script>
var pjax = new Pjax({
  selectors: [
    'head title',
    '#page-configurations',
    '.content-wrap',
    '.post-toc-wrap',
    '#pjax'
  ],
  switches: {
    '.post-toc-wrap': Pjax.switches.innerHTML
  },
  analytics: false,
  cacheBust: false,
  scrollTo : !CONFIG.bookmark.enable
});

window.addEventListener('pjax:success', () => {
  document.querySelectorAll('script[pjax], script#page-configurations, #pjax script').forEach(element => {
    var code = element.text || element.textContent || element.innerHTML || '';
    var parent = element.parentNode;
    parent.removeChild(element);
    var script = document.createElement('script');
    if (element.id) {
      script.id = element.id;
    }
    if (element.className) {
      script.className = element.className;
    }
    if (element.type) {
      script.type = element.type;
    }
    if (element.src) {
      script.src = element.src;
      // Force synchronous loading of peripheral JS.
      script.async = false;
    }
    if (element.getAttribute('pjax') !== null) {
      script.setAttribute('pjax', '');
    }
    if (code !== '') {
      script.appendChild(document.createTextNode(code));
    }
    parent.appendChild(script);
  });
  NexT.boot.refresh();
  // Define Motion Sequence & Bootstrap Motion.
  if (CONFIG.motion.enable) {
    NexT.motion.integrator
      .init()
      .add(NexT.motion.middleWares.subMenu)
      .add(NexT.motion.middleWares.postList)
      .bootstrap();
  }
  NexT.utils.updateSidebarPosition();
});
</script>




  















    <div id="pjax">
  

  
<script>window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };</script><script defer src="/_vercel/insights/script.js" data-endpoint="/this-is-vercel-insights"></script><script>window.si = window.si || function () { (window.siq = window.siq || []).push(arguments); };</script><script defer src="/_vercel/speed-insights/script.js" data-endpoint="/this-is-vercel-insights-speed"></script>
    </div>
</body>
</html>
